using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.IO;

namespace TripleT.SharePointLogParser
{
    struct LogFiles
    {
        public LogFiles(string name, DateTime modDate)
        {
            FileName = name;
            ModifiedDate = modDate;
        }

        public string FileName;
        public DateTime ModifiedDate;
    }

    public enum LogColumnNames
    {
        Timestamp=0
        ,Process
        ,TID
        ,Area
        ,Category
        ,EventID
        ,Level
        ,Message
        ,Correlation
        ,ProcessName
        ,ProcessHex
    }

    public partial class Form1 : Form
    {
        private string SHAREPOINT_LOG_DIR = @"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\LOGS\";

        private DataTable _logFileData;


        public Form1()
        {
            InitializeComponent();
            this.Name = "SharePoint 2007 Log Parser";
            this.Text = "SharePoint 2007 Log Parser";
            toolStripStatusLabel.Text = "";
            toolStripStatusLabel.IsLink = true;
            toolStripStatusLabel.LinkBehavior = LinkBehavior.SystemDefault;

            fileWatcher.Path = SHAREPOINT_LOG_DIR;
            fileWatcher.Changed += new FileSystemEventHandler(fileWatcher_Changed);
        }

        private void fileWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            if(logFileListBox.SelectedItem != null)
            {
                string labelText = string.Format("{0} updated at {1}",logFileListBox.SelectedItem,DateTime.Now);
                toolStripStatusLabel.Text = labelText;
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            DisplayLogFiles();

        }

        private void DisplayLogFiles()
        {
            //clear the listbox items
            logFileListBox.SuspendLayout();
            logFileListBox.Items.Clear();

            //add all the logs to the listbox
            DirectoryInfo logDir = new DirectoryInfo(SHAREPOINT_LOG_DIR);

            List<LogFiles> logs = new List<LogFiles>();
            foreach (FileInfo file in logDir.GetFiles("*.log"))
            {
                logs.Add(new LogFiles(file.Name, file.LastWriteTime));
            }

            //sort the data by modified date
            logs.Sort(delegate(LogFiles log1, LogFiles log2)
            {
                return Comparer<DateTime>.Default.Compare(log1.ModifiedDate, log2.ModifiedDate);
            });
            logs.Reverse();

            //loop over the sorted data and add it to the list box
            foreach (LogFiles log in logs)
            {
                logFileListBox.Items.Add(log.FileName);
            }

            logFileListBox.ResumeLayout();
        }

        private void logFileListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadLogFile();
        }

        private void LoadLogFile()
        {
            string fileSelected = logFileListBox.SelectedItem.ToString();
            fileWatcher.Filter = fileSelected;

            _logFileData = LogData();

            ReadLogFile(fileSelected);

            BindLogDataToGridView(null);

            LoadFilterControls();
        }



        private void LoadFilterControls()
        {
            LoadFilterControlData(comboBoxFilterProcessName,LogColumnNames.ProcessName);
            LoadFilterControlData(comboBoxFilterLevel, LogColumnNames.Level);
            LoadFilterControlData(comboBoxFilterArea, LogColumnNames.Area);
            LoadFilterControlData(comboBoxFilterCategory, LogColumnNames.Category);
        }

        private void LoadFilterControlData(ComboBox filterBox, LogColumnNames filterType)
        {
            //get the distinct values from data
            List<string> values = new List<string>();
            values.Add("");

            string colName = System.Enum.GetName(typeof(LogColumnNames), filterType);
            foreach (DataRow dr in _logFileData.Rows)
            {
                if (!values.Contains(dr[colName].ToString()))
                    values.Add(dr[colName].ToString());
            }

            filterBox.DataSource = values;
            filterBox.SelectedIndex = 0;
        }

        private void BindLogDataToGridView(DataView filteredLogData)
        {
            if (_logFileData != null || filteredLogData != null)
            {
                gridLogData.SuspendLayout();

                //DataGridViewTextBoxColumn textColumn0 = new DataGridViewTextBoxColumn();
                //textColumn0.DataPropertyName = "Column1";
                //gridLogData.Columns.Add(textColumn0);
                //textColumn0.SortMode = DataGridViewColumnSortMode.Programmatic;
                //textColumn0.HeaderCell.SortGlyphDirection = SortOrder.None;

                gridLogData.DataSource = filteredLogData == null? _logFileData.DefaultView : filteredLogData;
                gridLogData.Columns[2].Visible = false;
                gridLogData.Columns[5].Visible = false;
                gridLogData.Columns[8].Visible = false;

                gridLogData.ResumeLayout();
            }
        }

        private void ReadLogFile(string logFileName)
        {
            int line = 0;
            string logFileToRead = SHAREPOINT_LOG_DIR + logFileName;

            //get the file
            using (FileStream logFileStream = new FileStream(logFileToRead, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                //create stream reader from filestream
                using (StreamReader logFileReader = new StreamReader(logFileStream))
                {
                    //loop over data till end
                    while (!logFileReader.EndOfStream)
                    {
                        //split the current log file line at TABS
                        string[] strings = logFileReader.ReadLine().Split(new char[] { '\t' });

                        //the first line of the log file contains header text
                        if (line == 0)
                        {
                            line++;
                            continue;
                        }

                        //add the logfile data line to the log datatable
                        DataRow dr = _logFileData.NewRow();

                        //dr[(int)System.Enum.Parse(typeof(LogColumnNames), LogColumnNames.Timestamp.ToString())] = DateTime.Parse(strings[0].Replace("*", ""));

                        for (int i = 0; i < strings.Length; i++)
                        {
                            if (i == (int)LogColumnNames.Process)
                            {
                                if (strings[i].Contains("("))
                                {
                                    dr[i] = strings[i];
                                    dr[_logFileData.Columns.Count - 2] = strings[i].Substring(0, strings[i].IndexOf('('));
                                    dr[_logFileData.Columns.Count - 1] = strings[i].Substring(strings[i].IndexOf('('));
                                }
                            }
                            else
                                dr[i] = strings[i];
                        }

                        //add the datarow
                        _logFileData.Rows.Add(dr);

                        //increase the line count
                        line++;
                    }
                }
            }
        }
        
        public DataTable LogData()
        {
            //create the log file data table
            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn("Timestamp");//,typeof(DateTime));
            dt.Columns.Add(dc);
            dc = new DataColumn("Process");
            dt.Columns.Add(dc);
            dc = new DataColumn("TID");
            dt.Columns.Add(dc);
            dc = new DataColumn("Area");
            dt.Columns.Add(dc);
            dc = new DataColumn("Category");
            dt.Columns.Add(dc);
            dc = new DataColumn("EventID");
            dt.Columns.Add(dc);
            dc = new DataColumn("Level");
            dt.Columns.Add(dc);
            dc = new DataColumn("Message");
            dt.Columns.Add(dc);
            dc = new DataColumn("Correlation");
            dt.Columns.Add(dc);
            dc = new DataColumn("ProcessName");
            dt.Columns.Add(dc);
            dc = new DataColumn("ProcessHex");
            dt.Columns.Add(dc);

            return dt;
        }

        private void SetDataViewFilterData(ComboBox filterBox, LogColumnNames filterType)
        {
            if (gridLogData.DataSource != null || _logFileData != null)
            {
                //apply selected item filter
                if (!string.IsNullOrEmpty(filterBox.SelectedItem.ToString()))
                {
                    DataView dvFiltered = _logFileData.DefaultView;
                    dvFiltered.RowFilter = string.Format("{0} LIKE '{1}'", filterType, filterBox.SelectedItem);
                    BindLogDataToGridView(dvFiltered);
                }
            }
        }

        private void comboBoxFilterProcessName_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetDataViewFilterData((ComboBox)sender, LogColumnNames.ProcessName);
        }

        private void comboBoxFilterLevel_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetDataViewFilterData((ComboBox)sender, LogColumnNames.Level);
        }


        private void comboBoxFilterArea_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetDataViewFilterData((ComboBox)sender, LogColumnNames.Area);
        }

        private void comboBoxFilterCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetDataViewFilterData((ComboBox)sender, LogColumnNames.Category);
        }

    }
}